package client;

import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.material.Material;
import com.jme3.material.RenderState.FaceCullMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.util.SkyFactory;
import com.jme3.water.WaterFilter;

/**
 *
 * @author Ben
 */
public class TerrainControl
{
    static TerrainQuad terrain;
    Node terrainPhysicsNode;
    static Material matRock;
    Spatial sky;
    static Texture heightMapImage;
    static AbstractHeightMap heightmap;
    static TerrainLodControl control;
    private WaterFilter water;
    LundWidget lund = new LundWidget();
    private float waterHeight = 1.5f;
    
    public void loadTerrain()
    {
        Texture skytex = lund.loadTexture("Textures/sky.png");
        sky = SkyFactory.createSky(Main.appref.getAssetManager(), skytex,skytex,skytex,skytex,skytex,skytex);
        sky.setCullHint(CullHint.Dynamic);
        sky.setQueueBucket(Bucket.Sky);
        water = new WaterFilter(Main.appref.getRootNode(),new Vector3f(-.90f, -.90f, -.65f));
        water.setLightColor(ColorRGBA.LightGray);
        water.setWaterColor(ColorRGBA.Cyan);
        water.setDeepWaterColor(ColorRGBA.Blue.mult(0.1f));
        water.setWaterTransparency(0.02f);
        water.setShoreHardness(0.3f);
        water.setRefractionConstant(0.1f);
        water.setNormalScale(6f);
        water.setShininess(0.0f);
        //water.setLightDirection(new Vector3f(-.90f, -.90f, -.65f));
        water.setWindDirection(new Vector2f(0,0.5f));
        water.setSunScale(0.1f);
        water.setWaterHeight(waterHeight);
        matRock = new Material(Main.appref.getAssetManager(), "Materials/NewTerrainLighting.j3md");
        matRock.setTexture("AlphaMap", lund.loadTexture("Textures/alpha.png"));
        Texture grass = lund.loadTexture("Textures/grass.png");
        grass.setWrap(WrapMode.Repeat);
        Texture grass_normal = lund.loadTexture("Textures/grass_normals.png");
        grass_normal.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap", grass);
        matRock.setTexture("NormalMap",grass_normal);
        matRock.setFloat("DiffuseMap_0_scale", 64f);
        Texture dirt = lund.loadTexture("Textures/dirt.png");
        dirt.setWrap(WrapMode.Repeat);
        Texture dirt_normals = lund.loadTexture("Textures/dirt_normals.png");
        dirt_normals.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap_1", dirt);
        matRock.setTexture("NormalMap_1", dirt_normals);
        matRock.setFloat("DiffuseMap_1_scale", 32f);
        matRock.setFloat("Shininess",0.1f);
        Texture rock = lund.loadTexture("Textures/tile.png");
        Texture rock_normals = lund.loadTexture("Textures/tile_normals.png");
        rock.setWrap(WrapMode.Repeat);
        matRock.setTexture("DiffuseMap_2", rock);
        matRock.setTexture("NormalMap_2", rock_normals);
        matRock.setFloat("DiffuseMap_2_scale", 256f);
        Material terrainTex = new Material(Main.appref.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
        terrainTex.setTexture("DiffuseMap", Main.appref.getAssetManager().loadTexture("terrain.png"));
        terrainTex.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Back);
        terrainTex.setBoolean("VertexLighting", false);
        Main.gameScene = Main.appref.getAssetManager().loadModel("terrain.obj");
        Main.gameScene.setMaterial(terrainTex);
        CollisionShape sc = CollisionShapeFactory.createMeshShape(Main.gameScene);
        RigidBodyControl scl = new RigidBodyControl(sc, 0);
        Main.gameScene.addControl(scl);
        PhysicsController.addChild(Main.gameScene);
        Main.gameScene.setShadowMode(ShadowMode.CastAndReceive);
        Main.gameScene.setLocalTranslation(0, 0, 0);
        Main.rendernode.attachChild(Main.gameScene);
        Main.gameScene.setCullHint(CullHint.Dynamic);
        /*heightMapImage = lund.loadTexture("Textures/height.png");
        AbstractHeightMap heightmapImageB = new ImageBasedHeightMap(heightMapImage.getImage());
        heightmapImageB.setHeightScale(25f);
        heightmapImageB.load();
        terrain = new TerrainQuad("terrain", 129, 513, heightmapImageB.getHeightMap());
        control = new TerrainLodControl(terrain, Main.appref.getCamera());
        control.setLodCalculator( new DistanceLodCalculator(65, 1.8f) ); // patch size, and a multiplier
        terrain.addControl(control);
        terrain.setMaterial(matRock);
        terrain.setLocalScale(new Vector3f(2, 2, 2));
        terrain.setLocked(false); // unlock it so we can edit the height
        terrain.setShadowMode(ShadowMode.Receive);
        Main.rendernode.attachChild(terrain);
        terrain.addControl(new RigidBodyControl(0));
        //bulletAppState.getPhysicsSpace().addAll(terrain);*/
        Main.appref.getRootNode().attachChild(sky);
        //PhysicsController.addChild(terrain);
    }
    
    public void startWater()
    {
        Main.fpp.addFilter(water);
    }
    
    public static void reloadTerrain(int type)
    {
        if (type == 1)
        {
            if (Main.rendernode.hasChild(Main.gameScene))
            {
                Main.rendernode.detachChild(Main.gameScene);
            }
            if (Main.rendernode.hasChild(terrain))
            {
                Main.rendernode.detachChild(terrain);
            }
            AbstractHeightMap heightmapImageB = new ImageBasedHeightMap(heightMapImage.getImage());
            heightmapImageB.setHeightScale(25f);
            heightmapImageB.load();
            PhysicsController.softRemoveChild(terrain);
            if (terrain != null)
            {
                if (terrain.getControl(RigidBodyControl.class) != null)
                {
                    terrain.removeControl(RigidBodyControl.class);
                    terrain.removeControl(TerrainLodControl.class);
                }
            }
            terrain = new TerrainQuad("terrain", 129, 513, heightmapImageB.getHeightMap());
            control = new TerrainLodControl(terrain, Main.appref.getCamera());
            control.setLodCalculator(new DistanceLodCalculator(9, 1.8f));
            control.setTerrain(terrain);
            terrain.addControl(control);
            terrain.setMaterial(matRock);
            terrain.setLocalScale(new Vector3f(2, 2, 2));
            terrain.setShadowMode(ShadowMode.Receive);
            terrain.addControl(new RigidBodyControl(0));
            PhysicsController.addChild(terrain);
            Main.rendernode.attachChild(terrain);
        }
        else if(type == 0)
        {
            if(Main.rendernode.hasChild(Main.gameScene))
            {
                Main.rendernode.detachChild(Main.gameScene);
            }
            if(Main.rendernode.hasChild(terrain))
            {
                Main.rendernode.detachChild(terrain);
            }
            CollisionShape sc = CollisionShapeFactory.createMeshShape(Main.gameScene);
            RigidBodyControl scl = new RigidBodyControl(sc,0);
            Main.gameScene.addControl(scl);
            PhysicsController.addChild(Main.gameScene);
            Main.gameScene.setShadowMode(ShadowMode.CastAndReceive);
            Main.gameScene.setLocalTranslation(0, 0, 0);
            Main.rendernode.attachChild(Main.gameScene);
        }
    }
    
    public static TerrainQuad getTerrain()
    {
        return terrain;
    }
}
